using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ICP_MS.Plugin.Tune;

public class DetectorCalibration
{
	private bool isRunPA = false;

	private int sweepIndexPA = 0;

	public int SweepCountsPA = 10;

	public int dwelltime = 50;

	public int order = 0;

	public bool bStableFunEnd = false;

	public bool TuneSucceed = false;

	public double recommondPC1 = 400000.0;

	public double recommondPC2 = 4000000.0;

	private List<DetectorFactor> currentFactors = new List<DetectorFactor>();

	private PACurve currentCurve = null;

	private AutoResetEvent scanEvent = new AutoResetEvent(initialState: false);

	private Thread threadStable;

	public List<DetectorFactor> CurrentFactors => currentFactors;

	public PACurve CurrentCurve
	{
		get
		{
			return currentCurve;
		}
		set
		{
			currentCurve = value;
		}
	}

	public int TotalPoints => currentFactors.Count * SweepCountsPA;

	public event EventHandler EventTuneFinish;

	public event EventHandler<MsgEventArgs> EventTuneMsg;

	public event EventHandler RefreshTree = null;

	public event EventHandler RefreshDatas = null;

	public event EventHandler RefreshCurve = null;

	public event EventHandler RefreshProgress = null;

	public event EventHandler RefreshMsg = null;

	public event EventHandler CalibrationFinish = null;

	public bool Init()
	{
		if (!Detector.detectorConfig.IsNewBoard)
		{
			recommondPC1 = 400000.0;
			recommondPC2 = 4000000.0;
		}
		SelectCurrentFactors();
		SelectCurrentPACurve();
		return false;
	}

	private void Detector_errorReceive(object sender, ErrorMsgEventArgs e)
	{
		LensManager.x2lens.Etp = 0.0;
		LensManager.Instance.SetEtp();
		Stop();
	}

	public bool Dispose()
	{
		Detector.pulseReceive -= Detector_pulseReceive;
		Detector.finishReceive -= Detector_finishReceive;
		Detector.errorevent -= Detector_errorevent;
		return false;
	}

	public void CurveChanged(PACurve curve)
	{
		SaveCurrentDetectorCurve();
		SelectCurrentFactors();
	}

	private void SelectCurrentFactors()
	{
		currentFactors.Clear();
		IList<DetectorFactor> factors = DataBase.Instance.GetDetectorFactors();
		if (factors != null && factors.Count > 0)
		{
			currentFactors.AddRange(factors);
		}
	}

	private void SelectCurrentPACurve()
	{
		PACurve curve = DataBase.Instance.GetPACurves();
		if (curve != null)
		{
			currentCurve = curve;
		}
		else
		{
			currentCurve = new PACurve();
		}
	}

	private void SaveCurrentDetectorCurve()
	{
		if (currentCurve != null)
		{
			DataBase.Instance.DeletePACurve();
			if (DataBase.Instance.SavePACurve(currentCurve))
			{
			}
		}
	}

	private void SaveCurrentDetectorFactors()
	{
		DataBase.Instance.DeleteDetectorFactors();
		if (!DataBase.Instance.SaveDetectorFactors(currentFactors))
		{
			Console.WriteLine(DataBase.Instance.LastException.Message);
		}
	}

	private double[] SetMassAxisPA()
	{
		List<double> mass = new List<double>();
		for (int i = 0; i < currentFactors.Count; i++)
		{
			if (currentFactors[i].measured)
			{
				mass.Add(currentFactors[i].mass);
			}
		}
		return mass.ToArray();
	}

	private void Run()
	{
		if (this.RefreshMsg != null)
		{
			this.RefreshMsg("进样20s", null);
		}
		bool success = true;
		int updatetime = 20;
		int lefttime = updatetime;
		while (lefttime-- > 0)
		{
			if (this.RefreshProgress != null)
			{
				this.RefreshProgress(null, null);
			}
			Thread.Sleep(1000);
			if (this.RefreshMsg != null)
			{
				this.RefreshMsg($"进样{lefttime}s", null);
			}
			if (!isRunPA)
			{
				success = false;
				break;
			}
		}
		Detector.finishReceive += Detector_finishReceive;
		Detector.errorevent += Detector_errorevent;
		if (this.RefreshMsg != null)
		{
			this.RefreshMsg("稳定40s", null);
		}
		DateTime timestart = DateTime.Now;
		bool bStable = true;
		bool bStableThreadEnd = true;
		Task.Factory.StartNew(delegate
		{
			bStableThreadEnd = false;
			while (isRunPA && success && bStable)
			{
				List<double> list = new List<double>();
				foreach (DetectorFactor current in CurrentFactors)
				{
					if (current.measured)
					{
						list.Add(current.mass);
					}
				}
				List<int> list2 = new List<int>();
				for (int j = 0; j < list.Count; j++)
				{
					list2.Add(1);
				}
				Detector.Instance.SetMassAxis(list.ToArray());
				Detector.Instance.SendHopDatas(list.ToArray(), list2.ToArray(), true, false);
				if (!scanEvent.WaitOne(20000))
				{
					isRunPA = false;
					success = false;
					bStable = false;
					Stop();
					return;
				}
				Thread.Sleep(5);
			}
			bStableThreadEnd = true;
		});
		int stabletime = 40;
		int lefttime2 = stabletime;
		while (isRunPA && success && lefttime2-- > 0)
		{
			if (this.RefreshProgress != null)
			{
				this.RefreshProgress(null, null);
			}
			Thread.Sleep(1000);
			if (this.RefreshMsg != null)
			{
				this.RefreshMsg($"稳定{lefttime2}s", null);
			}
		}
		bStable = false;
		int WaitTime = 10;
		while (!bStableThreadEnd && isRunPA && WaitTime-- > 0)
		{
			Thread.Sleep(1000);
			this.RefreshMsg($"等待稳定程序结束,剩余{WaitTime}s", null);
		}
		if (WaitTime <= 0)
		{
			Log.InsertLog("PA校正", Lang.Txt("CheckExperiment.Text4"), "稳定程序出现出错", (Severity)3);
			return;
		}
		Detector.pulseReceive += Detector_pulseReceive;
		double[] mass = SetMassAxisPA();
		List<int> res = new List<int>();
		for (int i = 0; i < mass.Length; i++)
		{
			res.Add(1);
		}
		if (this.RefreshMsg != null)
		{
			this.RefreshMsg("开始采集PA数据", null);
		}
		sweepIndexPA = 0;
		while (sweepIndexPA < SweepCountsPA && isRunPA)
		{
			if (this.RefreshMsg != null)
			{
				this.RefreshMsg($"采集PA数据,扫描第{sweepIndexPA}次", null);
			}
			if (!isRunPA)
			{
				success = false;
				break;
			}
			if (sweepIndexPA == 0)
			{
				Detector.Instance.SetMassAxis(mass);
			}
			Detector.Instance.SendHopDatas(mass, res.ToArray(), true, false);
			if (!scanEvent.WaitOne(20000))
			{
				MessageBox.Show("采集数据扫描超时(30s)!");
				isRunPA = false;
				success = false;
				break;
			}
			sweepIndexPA++;
		}
		if (this.RefreshMsg != null)
		{
			this.RefreshMsg("处理数据", null);
		}
		if (success && isRunPA)
		{
			ProcessDatasPA();
		}
		Stop();
	}

	private void Detector_errorevent(object sender, EventArgs e)
	{
		isRunPA = false;
		scanEvent.Set();
		Stop();
	}

	public void Start()
	{
		double[] mass = SetMassAxisPA();
		if (mass.Count() == 0)
		{
			if (this.CalibrationFinish != null)
			{
				this.CalibrationFinish(null, null);
			}
		}
		else
		{
			Detector.Instance.UsePA = false;
			isRunPA = true;
			sweepIndexPA = 0;
			Task.Factory.StartNew(Run);
			Detector.Instance.ExperimentState = 2;
		}
	}

	public void Stop()
	{
		isRunPA = false;
		scanEvent.Set();
		Detector.Instance.Stop();
		Detector.Instance.UsePA = true;
		if (this.RefreshMsg != null)
		{
			this.RefreshMsg("", null);
		}
		if (this.CalibrationFinish != null)
		{
			this.CalibrationFinish(null, null);
		}
		Dispose();
	}

	public void Save()
	{
		SaveCurrentDetectorCurve();
		SaveCurrentDetectorFactors();
	}

	public bool Delete(DateTime time)
	{
		return DataBase.Instance.DeletePACurve(time) && DataBase.Instance.DeleteDetectorFactors(time);
	}

	private void ProcessDatasPA()
	{
		currentCurve = new PACurve();
		currentCurve.time = DateTime.Now;
		currentCurve.description = "default";
		currentCurve.used = true;
		int temp = 0;
		for (int i = 0; i < currentFactors.Count; i++)
		{
			if (currentFactors[i].measured)
			{
				double pulse = Detector.msDetectorPara.IntesnsityPulse[temp] / (double)SweepCountsPA;
				double analogue = Detector.msDetectorPara.IntesnsityAnalog[temp] / (double)SweepCountsPA;
				temp++;
				currentFactors[i].HighANA = Math.Round(analogue, 2);
				currentFactors[i].HighPC = Math.Round(pulse, 2);
				if (pulse > recommondPC1 && pulse < recommondPC2)
				{
					currentFactors[i].HighSuccess = true;
				}
				currentFactors[i].id = 0;
				if (currentFactors[i].HighSuccess)
				{
					currentFactors[i].factorK = currentFactors[i].HighPC / currentFactors[i].HighANA;
					currentFactors[i].factorK = Math.Round(currentFactors[i].factorK, 2);
					currentFactors[i].factorB = currentFactors[i].HighPC - currentFactors[i].factorK * currentFactors[i].HighANA;
					currentFactors[i].factorB = Math.Round(currentFactors[i].factorB, 2);
					currentFactors[i].time = currentCurve.time;
					currentFactors[i].include = true;
				}
			}
		}
		Save();
	}

	public void Calculate()
	{
		if (currentFactors.Count < 4 || currentCurve == null)
		{
			return;
		}
		IEnumerable<double> ms = from factor in currentFactors
			where factor.include
			select factor.mass;
		IEnumerable<double> f = from factor in currentFactors
			where factor.include
			select factor.factorK;
		IEnumerable<double> nms = from factor in currentFactors
			where !factor.include
			select factor.mass;
		IEnumerable<double> nf = from factor in currentFactors
			where !factor.include
			select factor.factorK;
		double[] param = LSFit.Polynomial(ms.ToArray(), f.ToArray(), 3);
		currentCurve.a0 = param[0];
		currentCurve.a1 = param[1];
		currentCurve.a2 = param[2];
		currentCurve.a3 = param[3];
		List<double> cf = new List<double>();
		List<double> cb = new List<double>();
		foreach (DetectorFactor factor2 in currentFactors)
		{
			factor2.calculateK = currentCurve.a0 + factor2.mass * currentCurve.a1 + factor2.mass * factor2.mass * currentCurve.a2 + factor2.mass * factor2.mass * factor2.mass * currentCurve.a3;
			factor2.calculateK = Math.Round(factor2.calculateK, 2);
			factor2.calculateB = factor2.HighPC - factor2.factorK * factor2.HighANA;
			factor2.calculateB = Math.Round(factor2.calculateB, 2);
			if (factor2.include)
			{
				cf.Add(factor2.calculateK);
				cb.Add(factor2.calculateB);
			}
			factor2.errorK = (factor2.calculateK - factor2.factorK) / factor2.factorK * 100.0;
			factor2.errorK = Math.Round(factor2.errorK, 2);
			factor2.errorB = (factor2.calculateB - factor2.factorB) / factor2.factorK * 100.0;
		}
		currentCurve.b = ((cb.Count() > 0) ? cb.Average() : 0.0);
		currentCurve.r = LSFit.Pearson(f, (IEnumerable<double>)cf);
		if (this.RefreshDatas != null)
		{
			this.RefreshDatas(null, null);
		}
		if (this.RefreshCurve != null)
		{
			this.RefreshCurve(null, null);
		}
	}

	private void Detector_pulseReceive(object sender, PointEventArgs e)
	{
		if (this.RefreshProgress != null)
		{
			this.RefreshProgress(null, null);
		}
	}

	private void Detector_finishReceive(object sender, EventArgs e)
	{
		scanEvent.Set();
	}

	public bool CreateLookupTable(string path)
	{
		try
		{
			if (currentCurve == null)
			{
				Log.InsertLog("校正", "PA校正工作曲线不存在!", "", (Severity)3);
				return false;
			}
			string tmpFile = Path.GetTempFileName();
			using (FileStream fs = new FileStream(tmpFile, FileMode.Create, FileAccess.Write))
			{
				using BinaryWriter bw = new BinaryWriter(fs);
				double i = 0.0;
				double a0 = currentCurve.a0;
				double a1 = currentCurve.a1;
				double a2 = currentCurve.a2;
				double a3 = currentCurve.a3;
				while (i <= 260.0)
				{
					double factor = a0 + a1 * i + a2 * i * i + a3 * i * i * i;
					i += 0.01;
					bw.Write(factor);
				}
			}
			if (File.Exists(path))
			{
				File.Delete(path);
			}
			File.Copy(tmpFile, path);
			File.Delete(tmpFile);
			return true;
		}
		catch (Exception ex)
		{
			Log.InsertLog("校正", "创建PA系数查找表!", ex.Message, (Severity)3);
		}
		return false;
	}
}
